/*
 * File Name:               UIView.cs
 *
 * Description:             UI基本逻辑基类
 * Author:                  lisiyu <576603306@qq.com>
 * Create Date:             2016/11/22
 */

using System;
using System.Collections.Generic;
using UnityEngine;

// todo 思考 UI事件与数据绑定 做自动回收的利弊
public abstract class UIView : ICache
{
    // 每个View都对应一个上下文来处理逻辑
    protected UIContext mContext;

    // 保存一个窗口的引用是为了处理window内部之间的通信
    protected UIWindow mOwner;

    // 处理嵌套的子节点逻辑
    private List<UIView> mChilds;

    // 数据绑定接口
    private XPropertyBingderMgr mPropertyBinderMgr;

    // UI界面模型光照资源文件;
    List<ResourceItem> modelLightResourceItems;

    protected bool Loaded
    {
        get { return mContext != null; }
    }

    public virtual void onSpawn(object args)
    {
        // 涉及到可变参数 初始化交给 onCreated
    }

    public void onCreated(UIContext context, UIWindow owner, object args = null)
    {
        mContext = context;
        mOwner = owner;
        mPropertyBinderMgr = XCachePool.Singleton.pop<XPropertyBingderMgr>();
        onCacheComponents();
        onAddListeners();
        onOpen(args);
    }

    public void LateUpdate()
    {
        onLateUpdate();
    }

    public virtual void onRecycle()
    {
        onClose();
        onRemoveListeners();
        onClearComponents();
        XCachePool.Singleton.push(mPropertyBinderMgr);
        mPropertyBinderMgr = null;
        mOwner = null;
        if (mNeedRecycleGameobject)
            GameObject.Destroy(mContext.gameObject);
        mContext = null;
        if (mChilds != null)
        {
            foreach (var child in mChilds)
            {
                XCachePool.Singleton.push(child);
            }
            mChilds = null;
        }

        if (modelLightResourceItems != null)
        {
            for (int i = 0; i < modelLightResourceItems.Count; i++)
            {
                modelLightResourceItems[i].Dispose();
            }

            modelLightResourceItems = null;
        }
    }

    /// <summary>
    /// 是否需要回收游戏对象 
    /// </summary>
    protected virtual bool mNeedRecycleGameobject
    {
        get
        {
            return false;
        }
    }

    /// <summary>
    /// 获取组件 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    protected T getComponent<T>(int id = -1) where T : Component
    {
        return mContext.getComponent<T>(id);
    }

    /// <summary>
    /// 获取语言包 
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    protected virtual string getLanguage(int id)
    {
        return mOwner.getLanguage(id);
    }

    /// <summary>
    /// 获取额外参数 
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    protected virtual string getParam(int id)
    {
        return mOwner.getParam(id);
    }

    /// <summary>
    /// 显示子节点(从设计上讲 每个Context仅能调用一次) 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="context"></param>
	protected T showView<T>(UIContext context, object args = null) where T : UIView, new()
    {
        if (mChilds == null)
            mChilds = new List<UIView>();
        T view = XCachePool.Singleton.pop<T>();
        view.onCreated(context, mOwner, args);
        mChilds.Add(view);

        return view;
    }

    /// <summary>
    /// 隐藏节点
    /// </summary>
    /// <param name="view"></param>
    protected void hideView(UIView view)
    {
        if (mChilds == null) return;
        if (!mChilds.Contains(view)) return;
        mChilds.Remove(view);

        XCachePool.Singleton.push(view);
    }

    #region 逻辑流水线

    /// <summary>
    /// 缓存需要用到的逻辑组件 
    /// </summary>
    protected virtual void onCacheComponents()
    {

    }

    /// <summary>
    /// 清除需要用到的逻辑组件 
    /// </summary>
    protected virtual void onClearComponents()
    {
    }

    /// <summary>
    /// 添加事件 
    /// </summary>
    protected virtual void onAddListeners()
    {

    }

    /// <summary>
    /// 清理事件 
    /// </summary>
    protected virtual void onRemoveListeners()
    {
    }

    /// <summary>
    /// 窗口打开时的处理 
    /// </summary>
	protected virtual void onOpen(object args)
    {

    }

    protected virtual void onLateUpdate()
    {
        if (mChilds != null)
        {
            for (int i = 0; i < mChilds.Count; i++)
            {
                mChilds[i].onLateUpdate();
            }
        }
    }

    /// <summary>
    /// 窗口关闭时的处理 
    /// </summary>
    protected virtual void onClose()
    {

    }

    #endregion 逻辑流水线

    #region 数据绑定

    /// <summary>
    /// 绑定属性变化侦听事件 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="property"></param>
    /// <param name="callback"></param>
    /// <returns></returns>
    protected IPropertybinder bindProperty<T>(XProperty<T> property, Action<T> callback, bool callOnFirst = true)
    {
        return mPropertyBinderMgr.bindProperty<T>(property, callback, callOnFirst);
    }

    protected void unbindProperties()
    {
        mPropertyBinderMgr.unbindProperties();
    }

    #endregion 数据绑定

    #region 内部通信

    ///// <summary>
    ///// 绑定消息处理函数 
    ///// </summary>
    ///// <param name="msgId">   </param>
    ///// <param name="callback"></param>
    //protected virtual void bindMessage(int msgId, Action<object[]> callback)
    //{
    //    mOwner.bindMessage(msgId, callback);
    //}

    ///// <summary>
    ///// 解绑消息处理函数 
    ///// </summary>
    ///// <param name="msgId">   </param>
    ///// <param name="callback"></param>
    //protected virtual void unbindMessage(int msgId, Action<object[]> callback)
    //{
    //    mOwner.unbindMessage(msgId, callback);
    //}

    ///// <summary>
    ///// 发送消息 
    ///// </summary>
    ///// <param name="msgId"></param>
    ///// <param name="args"> </param>
    //protected virtual void sendMessage(int msgId, params object[] args)
    //{
    //    mOwner.sendMessage(msgId, args);
    //}

    #endregion 内部通信

    #region 使用子类沙盒模式封装一些常用操作
    /// <summary>
    /// 打开指定窗口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="winName"></param>
    /// <param name="args"></param>
    protected static void openWindow<T>(string winName, object args = null) where T : UIWindow, new()
    {
        UIManager.Singleton.open<T>(winName, args);
    }

    /// <summary>
    /// 关闭指定窗口
    /// </summary>
    /// <param name="winName"></param>
    protected static void closeWindow(string winName)
    {
        UIManager.Singleton.close(winName);
    }
    #endregion 使用子类沙盒模式封装一些常用操作

    #region 工具集

    public static string getSpritePath(string spName)
    {
        var loadPath = "UI/Sprite";
        var pathParts = spName.Split('_');
        if (pathParts.Length > 1)
        {
            for (int i = 0; i < pathParts.Length - 1; i++)
            {
                var part = pathParts[i];
                loadPath += "/" + part;
            }
        }
        loadPath += "/" + spName;

        return loadPath;
    }

    public static Sprite GetSprite(string spName)
    {
        if (!string.IsNullOrEmpty(spName))
        {
            var loadPath = getSpritePath(spName);
            var sp = ResourceManager.Instance.LoadAssetSync<Sprite>(loadPath);
            if (sp == null)
                Debug.LogWarning("not found:" + spName);

            return sp;
        }
        else
            return null;
    }

    public static Texture2D GetTexture2D(string spName)
    {
        if (!string.IsNullOrEmpty(spName))
        {
            var loadPath = getSpritePath(spName);
            var sp = ResourceManager.Instance.LoadAssetSync<Texture2D>(loadPath);
            if (sp == null)
                Debug.LogWarning("not found:" + spName);

            return sp;
        }
        else
            return null;
    }

    public static Sprite getSprite(string spName)
    {
        if (!string.IsNullOrEmpty(spName))
        {
            var loadPath = "UI/Sprite" + spName;
            var sp = ResourceManager.Instance.LoadAssetSync<Sprite>(loadPath);
            if (sp == null)
                Debug.LogWarning("not found:" + spName);

            return sp;
        }
        else
            return null;
    }

    public static void SetLayerRecursively(Transform tf, int layer)
    {
        tf.gameObject.layer = layer;
        if (tf.childCount > 0)
        {
            for (int i = 0; i < tf.childCount; i++)
            {
                SetLayerRecursively(tf.GetChild(i), layer);
            }
        }
    }
    #endregion
}